package main

import (
	"fmt"
	"math"
	"math/rand"
	"time"
	"sync"
)

func main() {
	start := time.Now()
	samples := math.Pow(10, 7)
	
	numThreads := 10
	
	pc := make(chan float64)
	go createParallelSimulations(pc, numThreads, samples)
	heads := <- pc
	
	area := samples * 0.25
	
	pi := heads / area
	
	fmt.Printf("pi estimation - %f\n", pi)
	
	duration := time.Since(start)
	
	fmt.Println(duration)
}

func runSimulation(samples float64) float64 {
	var r1 float64
	var r2 float64
	var heads float64
	heads = 0
	for range make([]struct{}, int(samples)) {
		r1 = rand.Float64()
		r2 = rand.Float64()
		toss := math.Pow(r1-0.5, 2)+math.Pow(r2-0.5, 2)
		if toss < 0.25 {
    			heads++
		}
	}
	return heads
}

func createParallelSimulations(c chan float64, numChannels int, totalSamples float64) {
	sum := make(chan float64)

	wg := sync.WaitGroup{}
 	wg.Add(numChannels)

	samplesPer := totalSamples / float64(numChannels)

	for range make([]struct{}, numChannels) {
		go func() {
			result := runSimulation(samplesPer)
			temp := <- sum
			temp += result
			wg.Done()
			
			sum <- temp
		}()
	}

	sum <- 0

	wg.Wait()
	temp := <- sum
	c <- temp
}
